package main

import (
	"fmt"
	"log"
	"net/http"
	"runtime"
	"runtime/debug"
	"strconv"
	"time"
)

func sayhelloName(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hello world!") //这个写入到w的是输出到客户端的
}
func main() {
	http.HandleFunc("/", sayhelloName)       //设置访问的路由
	err := http.ListenAndServe(":9090", nil) //设置监听的端口
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}

// 关键就是http.HandleFunc，围绕它来实现中间件
// 定义四个类型，App(应用程序)、Context(请求上下文)、Filter(过滤器/中间件)、Router(路由)

// App会有一个Run方法，是整个web应用程序的入口，在main方法中执行Run，用于注册路由、中间件和启动端口监听，它包括全局处理Fitler、异常处理函数和路由集合。
//
// Context是每个请求的上下文，执行Filter的OnEntry/OnExist和Router的handler都会传入该参数，因为它们都是在一个管道对请求进行处理。
//
// IFilter是中间件接口，实现OnEntry和OnExist方法，OnEntry是在请求进入handler前进行处理，OnExist是在请求离开handler后进行处理。
//
// Router是路由对象，一个路由包括url路径，中间件集合和逻辑处理函数

// 应用程序
type App struct {
	globalFilters    []IFilter        //全局中间件
	exceptionHandler http.HandlerFunc //异常处理函数
	routers          []*Router        //路由集合
}

// 请求上下文
type Context struct {
	Request        *http.Request       //request
	ResponseWriter http.ResponseWriter //response
	StartTime      time.Time           //请求开始时间
	Exception      Exception           //异常
	IsEnd          bool                //判断请求是否结束
}

// 中间件接口
type IFilter interface {
	OnEntry(*Context) //在请求进入handler前执行
	OnExist(*Context) //在请求从handler处理完后执行
}

// 路由
type Router struct {
	path    string           //url路径
	filters []IFilter        //中间件
	handler http.HandlerFunc //处理函数
}

// 日志中间件
type LogFilter struct {
	Filter
}

func (filter *LogFilter) OnExist(ctx *Context) {
	ontryTime := ctx.StartTime
	existTime := time.Now()
	duration := existTime.Sub(ontryTime)
	//记录访问日志
	//	app.InfoLog.Info(ctx.Request.URL, " "+strconv.FormatInt(duration.Nanoseconds()/1000/1000, 10)+"ms")
	//这里先简单打印出来就好了
	fmt.Println(ctx.Request.URL, " "+strconv.FormatInt(duration.Nanoseconds()/1000/1000, 10)+"ms")
}

// 登录验证中间件
type LoginFilter struct {
	Filter
	ExcludedUrl []string //不需要经过LoginFilter的页面
}

func (filter *LoginFilter) OnEntry(context *Context) {
	//如果是不需要登录的页面，则直接返回
	url := context.Request.URL.Path
	if IndexOf(filter.ExcludedUrl, url) {
		return
	}
	//简单弄，如果cookie["token"]不为空就认为已经登录了，则返回，否则跳转到登录页面
	token, _ := context.Request.Cookie("token")
	if token == nil {
		if context.IsAjax() {
			result := model.JsonResult{IsSuccess: false, Message: "未登录，请先登录！"}
			resultJson, _ := json.Marshal(result)
			fmt.Fprintf(context.ResponseWriter, string(resultJson))
		} else {
			http.Redirect(context.ResponseWriter, context.Request, "/static/login.html", 301)
		}
		context.End()
	}
}

// 权限验证中间件
type RightFilter struct {
	Filter
	operationCode string
}

func (filter *RightFilter) OnEntry(context *Context) {
	token, err := context.Request.Cookie("token")
	if err == nil {
		username := token.Value
		if !isUserHasRight(username, filter.operationCode) {
			if context.IsAjax() {
				result := JsonResult{IsSuccess: false, Message: "无权访问！"}
				resultJson, _ := json.Marshal(result)
				fmt.Fprintf(context.ResponseWriter, string(resultJson))
			} else {
				fmt.Fprintf(context.ResponseWriter, "无权访问！")
			}
			context.End()
		}
	} else {
		fmt.Println(err)
	}

}

// 自定义异常处理函数
func ExceptionHandler(context *Context) {
	fmt.Println(context.Exception.Message, context.Exception.Stack)
	if context.IsAjax() {
		result := model.JsonResult{IsSuccess: false, Message: "系统异常，联系管理员\n异常信息：" + context.Exception.Message}
		resultJson, _ := json.Marshal(result)
		fmt.Fprintf(context.ResponseWriter, string(resultJson))
	} else {
		fmt.Fprintf(context.ResponseWriter, context.Exception.Message)
	}
}

// 启动应用程序
func (app App) Run(addr ...string) {
	for _, router := range app.routers {
		HandleFunc(router)
	}

	var address string
	if len(addr) > 0 {
		address = addr[0]
	} else {
		address = ":8080"
	}

	fmt.Println("Listen On localhost", address)
	err := http.ListenAndServe(address, nil) //设置监听的端口
	if err != nil {
		fmt.Println("ListenAndServe_Error: ", err)
	}
}

// 处理路由对象
func HandleFunc(router *Router) {

	http.HandleFunc(router.path, func(response http.ResponseWriter, request *http.Request) {

		ctx := &Context{ResponseWriter: response, Request: request, StartTime: time.Now()}

		//异常处理
		defer func() {
			if err := recover(); err != nil {
				switch err.(type) {
				case runtime.Error:
					ctx.Exception = Exception{Message: err.(runtime.Error).Error(), Stack: string(debug.Stack())}
				case string:
					ctx.Exception = Exception{Message: err.(string), Stack: ""}
				default:
					ctx.Exception = Exception{Message: "其它异常", Stack: ""}
				}

				if WebApp.exceptionHandler != nil {
					WebApp.exceptionHandler(ctx)
				}
			}
		}()

		//执行全局中间件
		if len(WebApp.globalFilters) > 0 {
			for _, filter := range WebApp.globalFilters {
				if ctx.IsEnd {
					break
				}
				defer filter.OnExist(ctx)
				filter.OnEntry(ctx)

			}
		}

		//执行路由中间件
		if len(router.filters) > 0 {
			for _, filter := range router.filters {
				if ctx.IsEnd {
					break
				}
				defer filter.OnExist(ctx)
				filter.OnEntry(ctx)
			}
		}

		//执行handler
		if !ctx.IsEnd {
			router.handler(ctx)
		}

	})

}
